package com.yanfan.modbus.frame.abs;


import com.yanfan.modbus.code.ExceptionCode;
import com.yanfan.modbus.code.FunctionCode;
import com.yanfan.modbus.exception.ModbusTransportException;
import com.yanfan.modbus.frame.*;
import io.netty.buffer.ByteBuf;


abstract public class ModbusRequest extends ModbusFrame {

    public ModbusRequest(int slaveId) throws ModbusTransportException {
        super(slaveId);
    }

    public static ModbusRequest createModbusRequest(ByteBuf buf) throws ModbusTransportException {
        int slaveId = buf.readUnsignedByte();
        byte functionCode = buf.readByte();

        ModbusRequest request = null;
        if (functionCode == FunctionCode.READ_COILS) {
            request = new ReadCoilsRequest(slaveId);
        } else if (functionCode == FunctionCode.READ_DISCRETE_INPUTS) {
            request = new ReadDiscreteInputsRequest(slaveId);
        } else if (functionCode == FunctionCode.READ_HOLDING_REGISTERS) {
            request = new ReadHoldingRegistersRequest(slaveId);
        } else if (functionCode == FunctionCode.READ_INPUT_REGISTERS) {
            request = new ReadInputRegistersRequest(slaveId);
        } else if (functionCode == FunctionCode.WRITE_COIL) {
            request = new WriteCoilRequest(slaveId);
        } else if (functionCode == FunctionCode.WRITE_REGISTER) {
            request = new WriteRegisterRequest(slaveId);
        } else if (functionCode == FunctionCode.READ_EXCEPTION_STATUS) {
            request = new ReadExceptionStatusRequest(slaveId);
        } else if (functionCode == FunctionCode.WRITE_COILS) {
            request = new WriteCoilsRequest(slaveId);
        } else if (functionCode == FunctionCode.WRITE_REGISTERS) {
            request = new WriteRegistersRequest(slaveId);
        } else if (functionCode == FunctionCode.REPORT_SLAVE_ID) {
            request = new ReportSlaveIdRequest(slaveId);
        } else if (functionCode == FunctionCode.WRITE_MASK_REGISTER) {
            request = new WriteMaskRegisterRequest(slaveId);
        } else {
            request = new ExceptionRequest(slaveId, functionCode, ExceptionCode.ILLEGAL_FUNCTION);
        }
        request.readRequest(buf);

        return request;

    }

    abstract public void validate() throws ModbusTransportException;


    abstract protected void readRequest(ByteBuf buf);


    @Override
    final protected void writeImpl(ByteBuf buf) {
        buf.writeByte(getFunctionCode());
        writeRequest(buf);
    }


    abstract protected void writeRequest(ByteBuf buf);
}
